/*
    Copyright (C) 2013-2014 Fredrik Johansson
    Copyright (C) 2022 Fredrik Johansson

    This file is part of Arb.

    Arb is free software: you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.  See <http://www.gnu.org/licenses/>.
*/

#include "flint/thread_support.h"
#include "arb.h"

#define HAVE_64_BIT (FLINT_BITS == 64)

/* one coefficient doesn't fit in 64 bits */
#define L24_FIXME 0
#define L24_FIXME_STR "19182937474703818751"

static const ulong log_atanh_4_x[] = {251, 449, 4801, 8749};
static const ulong log_atanh_4_den = 1;
static const slong log_atanh_4_c[] = {
    144, 54, -38, 62,
    228, 86, -60, 98,
    334, 126, -88, 144,
    404, 152, -106, 174,
};

static const ulong log_atanh_8_x[] = {57799, 74359, 87361, 388961, 672281, 1419263, 11819521, 23718421};
static const ulong log_atanh_8_den = 1;
static const slong log_atanh_8_c[] = {
    17078, 16538, 6790, 24056, 20056, 8490, -2564, 2356,
    27068, 26212, 10762, 38128, 31788, 13456, -4064, 3734,
    39654, 38400, 15766, 55856, 46568, 19712, -5954, 5470,
    47944, 46428, 19062, 67534, 56304, 23834, -7198, 6614,
    59080, 57212, 23490, 83220, 69382, 29370, -8870, 8150,
    63196, 61198, 25126, 89018, 74216, 31416, -9488, 8718,
    69806, 67598, 27754, 98328, 81978, 34702, -10480, 9630,
    72546, 70252, 28844, 102188, 85196, 36064, -10892, 10008,
};

#if HAVE_64_BIT
static const ulong log_atanh_12_x[] = {36171409, 42772001, 55989361, 100962049, 143687501, 287080366, 362074049, 617831551, 740512499, UWORD(3222617399), UWORD(6926399999), UWORD(9447152318)};
static const ulong log_atanh_12_den = 1;
static const slong log_atanh_12_c[] = {
    17325186, 3191278, 1683636, -1195752, 3410458, 18802224, 7208106, 6805862, -482400, -837914, 7774420, 9161220,
    27459770, 5058056, 2668500, -1895222, 5405448, 29800820, 11424578, 10787036, -764586, -1328062, 12322164, 14520190,
    40227836, 7409918, 3909282, -2776450, 7918838, 43657412, 16736704, 15802722, -1120098, -1945576, 18051644, 21271694,
    48637946, 8959050, 4726564, -3356900, 9574366, 52784516, 20235712, 19106470, -1354268, -2352322, 21825556, 25718796,
    59935296, 11040008, 5824424, -4136622, 11798246, 65045008, 24935950, 23544414, -1668830, -2898706, 26895074, 31692614,
    64110806, 11809132, 6230194, -4424808, 12620194, 69576496, 26673162, 25184682, -1785092, -3100650, 28768772, 33900542,
    70816054, 13044230, 6881800, -4887592, 13940120, 76853392, 29462866, 27818708, -1971792, -3424942, 31777652, 37446146,
    73596134, 13556318, 7151964, -5079468, 14487378, 79870484, 30619512, 28910808, -2049200, -3559398, 33025172, 38916198,
    78371552, 14435944, 7616032, -5409058, 15427418, 85053024, 32606314, 30786738, -2182166, -3790356, 35168070, 41441346,
    84165424, 15503168, 8179072, -5808940, 16567940, 91340846, 35016842, 33062748, -2343490, -4070570, 37767984, 44505032,
    85832372, 15810218, 8341064, -5923990, 16896078, 93149908, 35710372, 33717576, -2389904, -4151190, 38516002, 45386482,
    90254748, 16624814, 8770824, -6229214, 17766622, 97949308, 37550292, 35454820, -2513040, -4365074, 40500478, 47724948,
};
#endif

#if HAVE_64_BIT
static const ulong log_atanh_13_x[] = {51744295, 170918749, 265326335, 287080366, 362074049, 587270881, 831409151, WORD(2470954914), UWORD(3222617399), UWORD(6926399999), UWORD(9447152318), UWORD(90211378321), UWORD(127855050751)};
static const slong log_atanh_13_den = 1;
static const slong log_atanh_13_c[] = {
    3191278, 35138256, 17325186, 62225852, 26216928, 22419280, 9733920, 31220668, 40902078, -34447972, 9161220, 6323462, 19491222,
    5058056, 55692818, 27459770, 98625642, 41552848, 35533718, 15427898, 49483588, 64828260, -54598744, 14520190, 10022450, 30892856,
    7409918, 81588504, 40227836, 144483954, 60873822, 52055956, 22601462, 72492146, 94971684, -79985714, 21271694, 14682624, 45257216,
    8959050, 98645556, 48637946, 174690052, 73600222, 62938876, 27326568, 87647496, 114826650, -96707684, 25718796, 17752202, 54718778,
    11040008, 121558394, 59935296, 215266080, 90695670, 77557966, 33673830, 108005766, 141497942, -119170404, 31692614, 21875584, 67428550,
    11809132, 130026998, 64110806, 230263014, 97014162, 82961194, 36019784, 115530200, 151355674, -127472644, 33900542, 23399590, 72126092,
    13044230, 143626316, 70816054, 254345858, 107160720, 91637974, 39787036, 127613320, 167185724, -140804806, 37446146, 25846916, 79669646,
    13556318, 149264764, 73596134, 264330908, 111367610, 95235476, 41348986, 132623134, 173749062, -146332488, 38916198, 26861608, 82797298,
    14435944, 158950078, 78371552, 281482496, 118593898, 101415002, 44031990, 141228626, 185023084, -155827536, 41441346, 28604572, 88169750,
    15503168, 170700980, 84165424, 302292006, 127361338, 108912436, 47287198, 151669412, 198701518, -167347594, 44505032, 30719258, 94687986,
    15810218, 174081818, 85832372, 308279086, 129883808, 111069514, 48223750, 154673318, 202636924, -170662016, 45386482, 31327672, 96563340,
    16624814, 183051106, 90254748, 324162674, 136575864, 116792194, 50708402, 162642614, 213077468, -179455104, 47724948, 32941780, 101538612,
    17097438, 188255034, 92820584, 333378238, 140458556, 120112458, 52149982, 167266352, 219135010, -184556802, 49081712, 33878276, 104425236,
};
#else
/* Arndt formula with 32-bit x */
static const ulong log_atanh_13_x[] = { 51744295, 170918749, 265326335, 287080366, 362074049, 587270881, 617831551, 740512499, 831409151, 1752438401, UWORD(2151548801), UWORD(2470954914), UWORD(3222617399) };
static const slong log_atanh_13_den = 1;
static const slong log_atanh_13_c[] = {
    3191278, 35138256, 17325186, 62225852, 26216928, 22419280, 25814684, -19491222, 3410458, 24117970, -9161220, -9550766, 25945328,
    5058056, 55692818, 27459770, 98625642, 41552848, 35533718, 40915306, -30892856, 5405448, 38226078, -14520190, -15137606, 41122372,
    7409918, 81588504, 40227836, 144483954, 60873822, 52055956, 59939840, -45257216, 7918838, 56000192, -21271694, -22176192, 60243186,
    8959050, 98645556, 48637946, 174690052, 73600222, 62938876, 72470980, -54718778, 9574366, 67707702, -25718796, -26812390, 72837744,
    11040008, 121558394, 59935296, 215266080, 90695670, 77557966, 89304134, -67428550, 11798246, 83434468, -31692614, -33040222, 89756088,
    11809132, 130026998, 64110806, 230263014, 97014162, 82961194, 95525682, -72126092, 12620194, 89247094, -33900542, -35342034, 96009122,
    13044230, 143626316, 70816054, 254345858, 107160720, 91637974, 105516562, -79669646, 13940120, 98581306, -37446146, -39038402, 106050564,
    13556318, 149264764, 73596134, 264330908, 111367610, 95235476, 109658906, -82797298, 14487378, 102451388, -38916198, -40570962, 110213872,
    14435944, 158950078, 78371552, 281482496, 118593898, 101415002, 116774322, -88169750, 15427418, 109099132, -41441346, -43203482, 117365298,
    15503168, 170700980, 84165424, 302292006, 127361338, 108912436, 125407244, -94687986, 16567940, 117164640, -44505032, -46397440, 126041910,
    15810218, 174081818, 85832372, 308279086, 129883808, 111069514, 127891012, -96563340, 16896078, 119485158, -45386482, -47316370, 128538248,
    16624814, 183051106, 90254748, 324162674, 136575864, 116792194, 134480392, -101538612, 17766622, 125641440, -47724948, -49754270, 135160976,
    17097438, 188255034, 92820584, 333378238, 140458556, 120112458, 138303512, -104425236, 18271706, 129213278, -49081712, -51168726, 139003444,
};
#endif

#if HAVE_64_BIT
static const ulong log_atanh_16_x[] = {UWORD(9943658495), UWORD(15913962107), UWORD(19030755899), UWORD(22429958849), UWORD(22623739319), UWORD(36974504449), UWORD(90211378321), UWORD(123679505951), UWORD(127855050751), UWORD(187753824257), UWORD(384918250001), UWORD(569165414399), UWORD(842277599279), UWORD(1068652740673), UWORD(2218993446251), UWORD(2907159732049)};
static const ulong log_atanh_16_den = 1;
static const slong log_atanh_16_c[] = {
    WORD(2795845166), WORD(4115492742), WORD(653556516), WORD(2293232066), WORD(974581744), WORD(-2713448948), WORD(894308352), WORD(387970172), WORD(2837123522), WORD(1960851594), WORD(-546800620), WORD(-845945652), WORD(-60363442), WORD(2786163756), WORD(477501928), WORD(4560908494),
    WORD(4431309746), WORD(6522901668), WORD(1035862570), WORD(3634686830), WORD(1544675518), WORD(-4300714830), WORD(1417445202), WORD(614918174), WORD(4496734392), WORD(3107876246), WORD(-866658478), WORD(-1340792136), WORD(-95673792), WORD(4415965074), WORD(756822650), WORD(7228868932),
    WORD(6491751440), WORD(9555878222), WORD(1517511236), WORD(5324719962), WORD(2262908732), WORD(-6300433346), WORD(2076519688), WORD(900838842), WORD(6587596814), WORD(4552956406), WORD(-1269631722), WORD(-1964224976), WORD(-140159572), WORD(6469271902), WORD(1108725142), WORD(10590101570),
    WORD(7848929688), WORD(11553648806), WORD(1834765102), WORD(6437916328), WORD(2735996856), WORD(-7617614260), WORD(2510640954), WORD(1089169972), WORD(7964812684), WORD(5504806374), WORD(-1535063412), WORD(-2374869690), WORD(-169461606), WORD(7821750534), WORD(1340517388), WORD(12804088910),
    WORD(9672035168), WORD(14237265718), WORD(2260934076), WORD(7933279518), WORD(3371498900), WORD(-9386991086), WORD(3093798590), WORD(1342156280), WORD(9814834818), WORD(6783432004), WORD(-1891619354), WORD(-2926491136), WORD(-208823200), WORD(9638542992), WORD(1651885268), WORD(15778151054),
    WORD(10345856498), WORD(15229132802), WORD(2418446490), WORD(8485967020), WORD(3606380994), WORD(-10040954260), WORD(3309334146), WORD(1435660234), WORD(10498604566), WORD(7256013120), WORD(-2023402732), WORD(-3130370890), WORD(-223371278), WORD(10310031024), WORD(1766967100), WORD(16877366942),
    WORD(11427913226), WORD(16821923656), WORD(2671387974), WORD(9373500856), WORD(3983566664), WORD(-11091121746), WORD(3655452158), WORD(1585813662), WORD(11596636972), WORD(8014908028), WORD(-2235027216), WORD(-3457771418), WORD(-246733326), WORD(11388340822), WORD(1951771388), WORD(18642543992),
    WORD(11876547604), WORD(17482314850), WORD(2776260706), WORD(9741483588), WORD(4139952604), WORD(-11526534442), WORD(3798957054), WORD(1648069168), WORD(12051895068), WORD(8329555436), WORD(-2322769398), WORD(-3593515810), WORD(-256419526), WORD(11835421676), WORD(2028393578), WORD(19374408678),
    WORD(12647178828), WORD(18616686398), WORD(2956403392), WORD(10373577330), WORD(4408580900), WORD(-12274454430), WORD(4045459238), WORD(1755007110), WORD(12833904028), WORD(8870033672), WORD(-2473486482), WORD(-3826687568), WORD(-273057770), WORD(12603384370), WORD(2160009556), WORD(20631552148),
    WORD(13582162682), WORD(19992985526), WORD(3174965134), WORD(11140477794), WORD(4734499590), WORD(-13181883420), WORD(4344532978), WORD(1884751722), WORD(13782692150), WORD(9525779778), WORD(-2656347020), WORD(-4109587900), WORD(-293244454), WORD(13535130576), WORD(2319695292), WORD(22156806784),
    WORD(13851165806), WORD(20388958958), WORD(3237847280), WORD(11361121840), WORD(4828269280), WORD(-13442958766), WORD(4430579138), WORD(1922080394), WORD(14055666884), WORD(9714443732), WORD(-2708957614), WORD(-4190980828), WORD(-299052342), WORD(13803202200), WORD(2365638290), WORD(22595636032),
    WORD(14564825010), WORD(21439467516), WORD(3404672192), WORD(11946485504), WORD(5077038146), WORD(-14135585754), WORD(4658857654), WORD(2021112518), WORD(14779862680), WORD(10214964936), WORD(-2848532330), WORD(-4406914424), WORD(-314460536), WORD(14514390156), WORD(2487524026), WORD(23759840104),
    WORD(14978885874), WORD(22048966390), WORD(3501463022), WORD(12286110052), WORD(5221372376), WORD(-14537443850), WORD(4791303504), WORD(2078570372), WORD(15200036812), WORD(10505364388), WORD(-2929512758), WORD(-4532197824), WORD(-323400280), WORD(14927017216), WORD(2558241412), WORD(24435304444),
    WORD(15170996084), WORD(22331753214), WORD(3546370688), WORD(12443684334), WORD(5288338568), WORD(-14723892390), WORD(4852753890), WORD(2105228870), WORD(15394983372), WORD(10640099894), WORD(-2967084932), WORD(-4590325076), WORD(-327548018), WORD(15118462190), WORD(2591051882), WORD(24748697010),
    WORD(15529770390), WORD(22859870104), WORD(3630237738), WORD(12737961268), WORD(5413400890), WORD(-15072093276), WORD(4967515202), WORD(2155014792), WORD(15759054686), WORD(10891724404), WORD(-3037252628), WORD(-4698880288), WORD(-335294102), WORD(15475994138), WORD(2652326886), WORD(25333971474),
    WORD(16014378714), WORD(23573215058), WORD(3743519736), WORD(13135450858), WORD(5582326706), WORD(-15542419732), WORD(5122527102), WORD(2222262284), WORD(16250817854), WORD(11231601954), WORD(-3132030456), WORD(-4845509404), WORD(-345756994), WORD(15958924368), WORD(2735093060), WORD(26124521054),
};

static const ulong log_atanh_20_x[] = {UWORD(932784765626), UWORD(1986251708497), UWORD(2200009162625), UWORD(2218993446251), UWORD(2907159732049), UWORD(5175027061249), UWORD(7233275252995), UWORD(8152552404881), UWORD(8949772845287), UWORD(9164582675249), UWORD(12066279000049), UWORD(13055714577751), UWORD(22518692773919), UWORD(25640240468751), UWORD(31041668486401), UWORD(41257182408961), UWORD(63774701665793), UWORD(115445619421397), UWORD(121336489966251), UWORD(238178082107393)};
static const ulong log_atanh_20_den = 1;
static const slong log_atanh_20_c[] = {
    WORD(-116089335710), WORD(-440487517368), WORD(804976818014), WORD(-442021938612), WORD(2027028904414), WORD(-2259886314980), WORD(1755029607116), WORD(2232338696382), WORD(231770587740), WORD(419733644928), WORD(-445576594600), WORD(820684665848), WORD(282573414662), WORD(-955021371140), WORD(582451140742), WORD(1373640195020), WORD(-1386573872206), WORD(-391661105906), WORD(-546462355792), WORD(72583300802),
    WORD(-183997243834), WORD(-698156197064), WORD(1275858070502), WORD(-700588197196), WORD(3212764801374), WORD(-3581835065136), WORD(2781656114934), WORD(3538173122674), WORD(367347690338), WORD(665262087502), WORD(-706222193640), WORD(1300754420286), WORD(447868265940), WORD(-1513673060644), WORD(923163216578), WORD(2177168198590), WORD(-2197667591926), WORD(-620768165852), WORD(-866122341986), WORD(115041809950),
    WORD(-269551090102), WORD(-1022780342024), WORD(1869098289480), WORD(-1026343157820), WORD(4706615362308), WORD(-5247293526004), WORD(4075052552122), WORD(5183329936434), WORD(538154639242), WORD(974591342528), WORD(-1034596813426), WORD(1905570782676), WORD(656115150372), WORD(-2217490952868), WORD(1352409667588), WORD(3189493761084), WORD(-3219524829512), WORD(-909408925478), WORD(-1268846296712), WORD(168533205352),
    WORD(-325903968004), WORD(-1236604799988), WORD(2259855632194), WORD(-1240912465020), WORD(5690589571960), WORD(-6344302969650), WORD(4926991005894), WORD(6266967026988), WORD(650662300280), WORD(1178341314042), WORD(-1250891646004), WORD(2303953136126), WORD(793283866494), WORD(-2681083946940), WORD(1635147076820), WORD(3856295562626), WORD(-3892604984934), WORD(-1099531733444), WORD(-1534113784252), WORD(203767086766),
    WORD(-401603118542), WORD(-1523836445198), WORD(2784762256508), WORD(-1529144670566), WORD(7012367883822), WORD(-7817922172568), WORD(6071404914502), WORD(7722623069772), WORD(801794499498), WORD(1452039842670), WORD(-1541441759884), WORD(2839102481966), WORD(977543405268), WORD(-3303831127796), WORD(2014949892594), WORD(4752014323284), WORD(-4796757495086), WORD(-1354924813562), WORD(-1890449152022), WORD(251096965780),
    WORD(-429581588714), WORD(-1629997504614), WORD(2978768189562), WORD(-1635675537930), WORD(7500898267714), WORD(-8362573078436), WORD(6494381264686), WORD(8260634776436), WORD(857653088370), WORD(1553199050732), WORD(-1648829328132), WORD(3036894133574), WORD(1045645886906), WORD(-3533999013440), WORD(2155325335078), WORD(5083072736088), WORD(-5130933028848), WORD(-1449318312346), WORD(-2022151005842), WORD(268590129162),
    WORD(-474510845980), WORD(-1800476359276), WORD(3290312831700), WORD(-1806748249094), WORD(8285405324932), WORD(-9237201337930), WORD(7173618304380), WORD(9124601470546), WORD(947353665082), WORD(1715645676866), WORD(-1821277773358), WORD(3354518076038), WORD(1155008332356), WORD(-3903614367134), WORD(2380747394626), WORD(5614703254392), WORD(-5667569179290), WORD(-1600900216754), WORD(-2233644573442), WORD(296681544924),
    WORD(-493139083180), WORD(-1871159044356), WORD(3419483172926), WORD(-1877677154576), WORD(8610671853606), WORD(-9599833254658), WORD(7455238554976), WORD(9482812967686), WORD(984544656468), WORD(1782998098608), WORD(-1892777075548), WORD(3486208971918), WORD(1200351382710), WORD(-4056861558392), WORD(2474210225994), WORD(5835123977998), WORD(-5890065301166), WORD(-1663747987724), WORD(-2321332476230), WORD(308328600494),
    WORD(-525137302522), WORD(-1992572575684), WORD(3641362509476), WORD(-1999513625248), WORD(9169390835836), WORD(-10222735759458), WORD(7938985162504), WORD(10098122399988), WORD(1048428613234), WORD(1898691147874), WORD(-2015593331842), WORD(3712417932350), WORD(1278238348358), WORD(-4320098341710), WORD(2634753821522), WORD(6213746527504), WORD(-6272252817574), WORD(-1771703278344), WORD(-2471956323078), WORD(328335058154),
    WORD(-563959786616), WORD(-2139879987964), WORD(3910562083430), WORD(-2147334177206), WORD(9847267894216), WORD(-10978484769320), WORD(8525900477254), WORD(10844658961710), WORD(1125937110470), WORD(2039058070076), WORD(-2164602628440), WORD(3986870509682), WORD(1372736278156), WORD(-4639475670938), WORD(2829536572314), WORD(6673117961550), WORD(-6735949519516), WORD(-1902682209022), WORD(-2654703738990), WORD(352608295860),
    WORD(-575129358650), WORD(-2182261633316), WORD(3988013181752), WORD(-2189863457382), WORD(10042299119296), WORD(-11195920443568), WORD(8694761204194), WORD(11059444133150), WORD(1148236990638), WORD(2079442875048), WORD(-2207473920962), WORD(4065832943536), WORD(1399924168332), WORD(-4731363353242), WORD(2885577292444), WORD(6805283185968), WORD(-6869359161762), WORD(-1940366005802), WORD(-2707281786830), WORD(359591921030),
    WORD(-604761980628), WORD(-2294699179870), WORD(4193489193856), WORD(-2302692675784), WORD(10559712548326), WORD(-11772772369510), WORD(9142744893568), WORD(11629264335090), WORD(1207398068356), WORD(2186582849238), WORD(-2321210490384), WORD(4275318494622), WORD(1472053026048), WORD(-4975139296132), WORD(3034252055452), WORD(7155914537110), WORD(-7223291925256), WORD(-2040340266348), WORD(-2846770158570), WORD(378119320652),
    WORD(-621954653248), WORD(-2359934781684), WORD(4312705165022), WORD(-2368155523296), WORD(10859912770262), WORD(-12107458457030), WORD(9402662389768), WORD(11959870657788), WORD(1241722976958), WORD(2248744830790), WORD(-2387199777610), WORD(4396860776674), WORD(1513901764174), WORD(-5116576661404), WORD(3120512276674), WORD(7359348780454), WORD(-7428641628588), WORD(-2098344743078), WORD(-2927700489722), WORD(388868808714),
    WORD(-629931470760), WORD(-2390201890380), WORD(4368017335942), WORD(-2398528066296), WORD(10999195500784), WORD(-12262741460610), WORD(9523255300552), WORD(12113260788736), WORD(1257648571430), WORD(2277585883836), WORD(-2417816570798), WORD(4453252277016), WORD(1533318160596), WORD(-5182198806204), WORD(3160534096344), WORD(7453735375880), WORD(-7523916932542), WORD(-2125256854766), WORD(-2965249421006), WORD(393856206922),
    WORD(-644828529934), WORD(-2446727053276), WORD(4471315259200), WORD(-2455250132412), WORD(11259312154488), WORD(-12552739331248), WORD(9748467890052), WORD(12399723636094), WORD(1287390322808), WORD(2331447824792), WORD(-2474994784934), WORD(4558565895664), WORD(1569579138862), WORD(-5304751061248), WORD(3235276613012), WORD(7630006513476), WORD(-7701847772584), WORD(-2175516412502), WORD(-3035373709344), WORD(403170393454),
    WORD(-664950480570), WORD(-2523077460712), WORD(4610843181352), WORD(-2531866503542), WORD(11610660323584), WORD(-12944449048562), WORD(10052669984964), WORD(12786658480520), WORD(1327563490282), WORD(2404200930252), WORD(-2552227290284), WORD(4700816484258), WORD(1618558041758), WORD(-5470286446298), WORD(3336233802840), WORD(7868101770266), WORD(-7942184844372), WORD(-2243403659776), WORD(-3130092905390), WORD(415751373324),
    WORD(-682912123820), WORD(-2591230832376), WORD(4735391283388), WORD(-2600257284842), WORD(11924287495408), WORD(-13294104523166), WORD(10324212719726), WORD(13132051716094), WORD(1363423637016), WORD(2469143208920), WORD(-2621168057182), WORD(4827794945270), WORD(1662278533696), WORD(-5618049830928), WORD(3426352154678), WORD(8080634945560), WORD(-8156719151760), WORD(-2304002482364), WORD(-3214642979038), WORD(426981649964),
    WORD(-688495357788), WORD(-2612415765984), WORD(4774106070468), WORD(-2621516015348), WORD(12021776007726), WORD(-13402792146898), WORD(10408619619450), WORD(13239414456718), WORD(1374570478458), WORD(2489329999806), WORD(-2642597746338), WORD(4867265190110), WORD(1675868700938), WORD(-5663980903990), WORD(3454364727704), WORD(8146699192982), WORD(-8223405435180), WORD(-2322839144468), WORD(-3240924697068), WORD(430472492150),
    WORD(-704208264478), WORD(-2672036567638), WORD(4883061174324), WORD(-2681344503760), WORD(12296138125812), WORD(-13708671946964), WORD(10646166128660), WORD(13541565635564), WORD(1405941056956), WORD(2546141726370), WORD(-2702907364024), WORD(4978346380276), WORD(1714115536192), WORD(-5793244816128), WORD(3533200568824), WORD(8332623938590), WORD(-8411080777960), WORD(-2375851200860), WORD(-3314889389462), WORD(440296776404),
    WORD(-713920057888), WORD(-2708886841112), WORD(4950403867850), WORD(-2718323143738), WORD(12465715166074), WORD(-13897729355958), WORD(10792988271008), WORD(13728318467836), WORD(1425330504340), WORD(2581255773856), WORD(-2740183379160), WORD(5047003159822), WORD(1737755042866), WORD(-5873139926234), WORD(3581927225030), WORD(8447539832562), WORD(-8527078676580), WORD(-2408616757868), WORD(-3360605298450), WORD(446368945032),
};

static const ulong log_atanh_24_x[] = {UWORD(134543112911873), UWORD(148569359956291), UWORD(166019820559361), UWORD(201842423186689), UWORD(206315395261249), UWORD(211089142289024), UWORD(217172824950401), UWORD(238178082107393), UWORD(259476225058051), UWORD(330190746672799), UWORD(386624124661501), UWORD(473599589105798), UWORD(478877529936961), UWORD(1796745215731101), UWORD(1814660314218751), UWORD(2767427997467797), UWORD(2838712971108351), UWORD(4573663454608289), UWORD(9747977591754401), UWORD(11305332448031249), UWORD(17431549081705001), UWORD(34903240221563713), UWORD(332110803172167361), L24_FIXME};
static const ulong log_atanh_24_den = 2;
static const slong log_atanh_24_c[] = {
    WORD(95300949339891), WORD(8383110436820), WORD(-33446555503183), WORD(-57342856225640), WORD(52380491656263), WORD(102208933748031), WORD(6896245322375), WORD(38607613905573), WORD(-85720402524046), WORD(25043219434553), WORD(131214305964926), WORD(114563664023695), WORD(-76722528792182), WORD(-31877386468039), WORD(-22332023559694), WORD(3666995585797), WORD(90133674519724), WORD(45155648723502), WORD(-3541965146654), WORD(-61019828808695), WORD(35149960568702), WORD(-16630104641178), WORD(-24161266171881), WORD(-23606318798422),
    WORD(151048430986854), WORD(13286915681764), WORD(-53011536250834), WORD(-90886276801884), WORD(83021115044514), WORD(161997327229322), WORD(10930290231738), WORD(61191620282654), WORD(-135863623547336), WORD(39692563701098), WORD(207969754512560), WORD(181579111422774), WORD(-121602331096108), WORD(-50524462172838), WORD(-35395419907336), WORD(5812050493798), WORD(142858494165968), WORD(71570009922488), WORD(-5613881936308), WORD(-96714140462206), WORD(55711369403220), WORD(-26358092239336), WORD(-38294700852374), WORD(-37415130075568),
    WORD(221281951741730), WORD(19464979645796), WORD(-77660496900050), WORD(-133145988911400), WORD(121623735200690), WORD(237321794818034), WORD(16012585763258), WORD(89644103403914), WORD(-199036610925636), WORD(58148554791518), WORD(304670183471108), WORD(266008590149854), WORD(-178144195113372), WORD(-74016999231722), WORD(-51853352918940), WORD(8514500074490), WORD(209283911162780), WORD(104848169413964), WORD(-8224188385128), WORD(-141683654856126), WORD(81615680978652), WORD(-38613907187268), WORD(-56100722732542), WORD(-54812174834924),
    WORD(267543589206106), WORD(23534366346960), WORD(-93896352217734), WORD(-160981749669892), WORD(147050631071006), WORD(286936753235794), WORD(19360208249486), WORD(108385274926710), WORD(-240647593946640), WORD(70305205343762), WORD(368365127695008), WORD(321620866085874), WORD(-215387368837440), WORD(-89491137803382), WORD(-62693916259812), WORD(10294558106950), WORD(253037214806084), WORD(126767932702628), WORD(-9943553288216), WORD(-171304316749202), WORD(98678414812676), WORD(-46686606118744), WORD(-67829249510774), WORD(-66271315270412),
    WORD(329687117432571), WORD(29000797307664), WORD(-115706071642219), WORD(-198373689929952), WORD(181206729035443), WORD(353584817115143), WORD(23857089118103), WORD(133560400265081), WORD(-296543870854002), WORD(86635305144365), WORD(453926918872614), WORD(396325161670511), WORD(-265416341965486), WORD(-110277638667055), WORD(-77256108410558), WORD(12685720474909), WORD(311811283537496), WORD(156212878954162), WORD(-12253186220446), WORD(-211093925144635), WORD(121598884985222), WORD(-57530709816938), WORD(-83584248141317), WORD(-81664445650894),
    WORD(352655418113885), WORD(31021194821972), WORD(-123766962418989), WORD(-212193782729012), WORD(193830851780593), WORD(378217997990065), WORD(25519140096961), WORD(142865147918839), WORD(-317203182155022), WORD(92670923865743), WORD(485550629380930), WORD(423935932609053), WORD(-283907092818814), WORD(-117960346996865), WORD(-82638306966754), WORD(13569496111931), WORD(333534229134788), WORD(167095756034874), WORD(-13106828508950), WORD(-225800198117865), WORD(130070310179518), WORD(-61538699731058), WORD(-89407308983007), WORD(-87353759680782),
    WORD(389539089162686), WORD(34265652404600), WORD(-136711552787078), WORD(-234386794033464), WORD(214103313251398), WORD(417775218738894), WORD(28188146499354), WORD(157807187228370), WORD(-350378960054060), WORD(102363228864014), WORD(536333599872088), WORD(468274719654342), WORD(-313600485524804), WORD(-130297632664286), WORD(-91281316470176), WORD(14988708195974), WORD(368418045344724), WORD(184572036229868), WORD(-14477650921952), WORD(-249416282834998), WORD(143674157695984), WORD(-67974934766920), WORD(-98758277675122), WORD(-96489950907260),
    WORD(404831524758217), WORD(35610845472804), WORD(-142078543351889), WORD(-243588296660336), WORD(222508531674341), WORD(434176141787993), WORD(29294750244373), WORD(164002345337891), WORD(-364134056345354), WORD(106381780861243), WORD(557388860465814), WORD(486658140447161), WORD(-325911740957278), WORD(-135412827034257), WORD(-94864817310094), WORD(15577131440583), WORD(382881315880104), WORD(191817922599958), WORD(-15046011198130), WORD(-259207809662073), WORD(149314484596246), WORD(-70643479056706), WORD(-102635307331167), WORD(-100277931114938),
    WORD(431099748810048), WORD(37921519445424), WORD(-151297566035348), WORD(-259393962873952), WORD(236946399295832), WORD(462348444271744), WORD(31195592979932), WORD(174643933477388), WORD(-387761551715668), WORD(113284554691332), WORD(593556042553364), WORD(518235832124084), WORD(-347059112416804), WORD(-144199332685348), WORD(-101020292176400), WORD(16587881724940), WORD(407725261017048), WORD(204264374666708), WORD(-16022298787084), WORD(-276026976164124), WORD(159003024385484), WORD(-75227308680080), WORD(-109294984465288), WORD(-106784645639096),
    WORD(462970200710807), WORD(40724991182128), WORD(-162482730986943), WORD(-278570505750492), WORD(254463432981563), WORD(496529057680187), WORD(33501828713835), WORD(187555054620497), WORD(-416428086356502), WORD(121659484069869), WORD(637436604666466), WORD(556548102559291), WORD(-372716586770550), WORD(-154859737636071), WORD(-108488546035734), WORD(17814194865017), WORD(437867677837832), WORD(219365283321430), WORD(-17206799367850), WORD(-296433168678579), WORD(170757840422238), WORD(-80788732293826), WORD(-117374971881217), WORD(-114679048087658),
    WORD(472139611596056), WORD(41531574795660), WORD(-165700801869020), WORD(-284087766740112), WORD(259503238499708), WORD(506363122463072), WORD(34165353131632), WORD(191269698363832), WORD(-424675701909508), WORD(124069025322872), WORD(650061430481412), WORD(567570881610592), WORD(-380098469065780), WORD(-157926830424736), WORD(-110637228722908), WORD(18167016001360), WORD(446539917747228), WORD(223709948299100), WORD(-17547590661072), WORD(-302304210744476), WORD(174139804959708), WORD(-82388803054672), WORD(-119699655723008), WORD(-116950337492960),
    WORD(496465851286329), WORD(43671422879532), WORD(-174238271134753), WORD(-298724935359436), WORD(272873728552017), WORD(532452673911025), WORD(35925668404849), WORD(201124564199291), WORD(-446556439431958), WORD(130461483769519), WORD(683554807827650), WORD(596814065127021), WORD(-399682435835998), WORD(-166063758223381), WORD(-116337635294350), WORD(19103042496175), WORD(469547174083276), WORD(235236246219806), WORD(-18451702254178), WORD(-317879952557557), WORD(183112080386350), WORD(-86633754593746), WORD(-125866989376963), WORD(-122976016914550),
    WORD(510579792177940), WORD(44912950125720), WORD(-179191660483648), WORD(-307217334322204), WORD(280631208075892), WORD(547589677891640), WORD(36946992951228), WORD(206842299273324), WORD(-459251514379372), WORD(134170350483680), WORD(702987467956960), WORD(613780787846540), WORD(-411044937929924), WORD(-170784755773828), WORD(-119644977589416), WORD(19646119551612), WORD(482895848606740), WORD(241923736338428), WORD(-18976262471744), WORD(-326916906155476), WORD(188317741707096), WORD(-89096650457352), WORD(-129445240013272), WORD(-126472080600140),
    WORD(517128182492702), WORD(45488976698092), WORD(-181489865293110), WORD(-311157519671140), WORD(284230415708346), WORD(554612734812622), WORD(37420852932582), WORD(209495134598958), WORD(-465141598975108), WORD(135891138961986), WORD(712003563770176), WORD(621652772261310), WORD(-416316753876636), WORD(-172975138663538), WORD(-121179472343144), WORD(19898088902858), WORD(489089181258168), WORD(245026505144048), WORD(-19219640637672), WORD(-331109746402578), WORD(190732992163116), WORD(-90239350681432), WORD(-131105427057454), WORD(-128094135684140),
    WORD(529357590757654), WORD(46564731774744), WORD(-185781864324998), WORD(-318515989914292), WORD(290952094999270), WORD(567728603938670), WORD(38305807386098), WORD(214449421789770), WORD(-476141592221384), WORD(139104787481286), WORD(728841521093396), WORD(636354050993358), WORD(-426162103101572), WORD(-177065775495990), WORD(-124045209100076), WORD(20368652800018), WORD(500655503647996), WORD(250821062989836), WORD(-19674160116636), WORD(-338940060832054), WORD(195243579111820), WORD(-92373393842120), WORD(-134205899720746), WORD(-131123395226864),
    WORD(545876257063253), WORD(48017789743924), WORD(-191579209401365), WORD(-328455319097920), WORD(300031289577985), WORD(585444642254441), WORD(39501144641717), WORD(221141341391611), WORD(-490999646990874), WORD(143445568847291), WORD(751585107067814), WORD(656211554511029), WORD(-439460541994554), WORD(-182591133988297), WORD(-127916054539358), WORD(21004259022679), WORD(516278517926468), WORD(258647963962418), WORD(-20288094612870), WORD(-349516725567269), WORD(201336178118558), WORD(-95255916535730), WORD(-138393810714063), WORD(-135215116302422),
    WORD(560621467231895), WORD(49314846343192), WORD(-196754147255895), WORD(-337327554606316), WORD(308135735163871), WORD(601258673695539), WORD(40568149612363), WORD(227114811594065), WORD(-504262530096578), WORD(147320320740317), WORD(771886924961410), WORD(673937141878415), WORD(-451331250728794), WORD(-187523285938031), WORD(-131371323171618), WORD(21571626094829), WORD(530224233926896), WORD(265634563102734), WORD(-20836116651046), WORD(-358957871814719), WORD(206774671224818), WORD(-97828969477586), WORD(-142132104509797), WORD(-138867547200558),
    WORD(565204898555282), WORD(49718026072564), WORD(-198362735535598), WORD(-340085418459904), WORD(310654937625698), WORD(606174339611938), WORD(40899819622402), WORD(228971617303994), WORD(-508385191840280), WORD(148524756553286), WORD(778197583608588), WORD(679446999753338), WORD(-455021166140040), WORD(-189056406149922), WORD(-132445365948808), WORD(21747987637362), WORD(534559148845864), WORD(267806291886348), WORD(-21006464943608), WORD(-361892577047422), WORD(208465183558664), WORD(-98628782523012), WORD(-143294123408370), WORD(-140002876300216),
    WORD(578104058631076), WORD(50852695603208), WORD(-202889788795904), WORD(-347846880300328), WORD(317744734226920), WORD(620008508177144), WORD(41833239204804), WORD(234197229381964), WORD(-519987607152804), WORD(151914402706204), WORD(795957683047256), WORD(694953403953372), WORD(-465405702570840), WORD(-193371069473816), WORD(-135468046716508), WORD(22244322284460), WORD(546758908700336), WORD(273918192609744), WORD(-21485876489096), WORD(-370151723940008), WORD(213222795850820), WORD(-100879698000032), WORD(-146564395553020), WORD(-143198035289608),
    WORD(586076738689057), WORD(51554009261324), WORD(-205687858363053), WORD(-352644064897800), WORD(322126777681341), WORD(628559095904597), WORD(42410164806673), WORD(237427062406747), WORD(-527158798505034), WORD(154009466580767), WORD(806934800145610), WORD(704537562829621), WORD(-471824150440838), WORD(-196037865609161), WORD(-137336297558938), WORD(22551095540991), WORD(554299305248044), WORD(277695820666722), WORD(-21782189958022), WORD(-375256516448941), WORD(216163368758078), WORD(-102270938114146), WORD(-148585677044111), WORD(-145172891032706),
    WORD(589896156708638), WORD(51889982861632), WORD(-207028310663546), WORD(-354942219741792), WORD(324226053660146), WORD(632655368250502), WORD(42686548660498), WORD(238974356712474), WORD(-530594252740420), WORD(155013134689418), WORD(812193533538096), WORD(709128981129146), WORD(-474898992937228), WORD(-197315429632778), WORD(-138231307879280), WORD(22698059334270), WORD(557911632124284), WORD(279505543440892), WORD(-21924142851456), WORD(-377702034938714), WORD(217572089171816), WORD(-102937430124708), WORD(-149553998724346), WORD(-146118971843224),
    WORD(600756289731806), WORD(52845290181468), WORD(-210839752673802), WORD(-361476793120676), WORD(330195134882802), WORD(644302708852546), WORD(43472418497894), WORD(243373933271006), WORD(-540362623157072), WORD(157866964543910), WORD(827146215827120), WORD(722184219713198), WORD(-483641999951620), WORD(-200948055119426), WORD(-140776180183436), WORD(23115936177398), WORD(568182922199896), WORD(284651309094660), WORD(-22327771702192), WORD(-384655622101314), WORD(221577644732168), WORD(-104832533477228), WORD(-152307324545886), WORD(-148809057976824),
    WORD(607547309886602), WORD(53442659592064), WORD(-213223110175526), WORD(-365562969544512), WORD(333927699742014), WORD(651585982879622), WORD(43963835858382), WORD(246125060998246), WORD(-546470946161724), WORD(159651511383150), WORD(836496374483224), WORD(730347875550638), WORD(-489109146322812), WORD(-203219595702034), WORD(-142367530774816), WORD(23377241454030), WORD(574605729155428), WORD(287869041160376), WORD(-22580167474376), WORD(-389003814749470), WORD(224082384635764), WORD(-106017572834936), WORD(-154029024557010), WORD(-150491213168888),
    WORD(617143543643169), WORD(54286788511200), WORD(-216590977622637), WORD(-371337051087476), WORD(339202100948917), WORD(661877809215553), WORD(44658246382249), WORD(250012616058163), WORD(-555102476340862), WORD(162173213311363), WORD(849708867758126), WORD(741883749092245), WORD(-496834644607818), WORD(-206429457242917), WORD(-144616231546638), WORD(23746485906151), WORD(583681649343220), WORD(292415944035758), WORD(-22936822111506), WORD(-395148145368313), WORD(227621774751894), WORD(-107692124585346), WORD(-156461919083727), WORD(-152868227824994),
};
#endif

/* Consecutively, real and imaginary parts of first 64 nonreal
   Gaussian primes. */
static const signed char small_gaussian_primes[] = {
    1, 1, 1, 2, 2, 3, 1, 4, 2, 5, 1, 6, 4, 5, 2, 7, 5, 6, 3, 8, 5, 8, 4, 9,
    1, 10, 3, 10, 7, 8, 4, 11, 7, 10, 6, 11, 2, 13, 9, 10, 7, 12, 1, 14, 2, 15, 8, 13, 
    4, 15, 1, 16, 10, 13, 9, 14, 5, 16, 2, 17, 12, 13, 11, 14, 9, 16, 5, 18, 8, 17, 7, 18, 
    10, 17, 6, 19, 1, 20, 3, 20, 14, 15, 12, 17, 7, 20, 4, 21, 10, 19, 5, 22, 11, 20, 10, 21, 
    14, 19, 13, 20, 1, 24, 8, 23, 5, 24, 17, 18, 16, 19, 4, 25, 13, 22, 6, 25, 12, 23, 1, 26, 
    5, 26, 15, 22, 2, 27, 9, 26
};

static const ulong atan_3_x[] = { 18, 57, 239 };
static const ulong atan_3_den = 1;
static const slong atan_3_c[] = {
    12, 8, -5,
    17, 11, -7,
    15, 10, -6,
};

static const ulong atan_4_x[] = { 38, 57, 239, 268 };
static const ulong atan_4_den = 1;
static const slong atan_4_c[] = {
    12, 20, 7, 24,
    17, 28, 10, 34,
    15, 25, 9, 30,
    20, 34, 12, 41,
};

static const ulong atan_8_x[] = { 931, 1772, 2943, 6118, 34208, 44179, 85353, 485298 };
static const ulong atan_8_den = 1;
static const slong atan_8_c[] = {
    398, 525, 163, 68, -295, 71, 215, -183,
    561, 740, 230, 96, -416, 100, 303, -258,
    498, 657, 204, 85, -369, 89, 269, -229,
    672, 886, 275, 115, -498, 120, 363, -309,
    603, 796, 247, 103, -447, 108, 326, -277,
    712, 940, 292, 122, -529, 127, 385, -328,
    454, 599, 186, 78, -337, 81, 245, -209,
    655, 864, 268, 112, -485, 117, 354, -301,
};

static const ulong atan_12_x[] = { 157318, 330182, 390112, 478707, 485298, 617427, 1984933, 2343692, 3449051, 6225244, 22709274, 24208144 };
static const ulong atan_12_den = 1;
static const slong atan_12_c[] = {
    96032, 52094, 29861, 50539, -56156, -13587, -91675, 50539, 19970, -52094, 23407, -25106,
    135373, 73435, 42094, 71243, -79161, -19153, -129231, 71243, 28151, -73435, 32996, -35391,
    120168, 65187, 37366, 63241, -70270, -17002, -114716, 63241, 24989, -65187, 29290, -31416,
    162110, 87939, 50408, 85314, -94796, -22936, -154755, 85314, 33711, -87939, 39513, -42381,
    145539, 78950, 45255, 76593, -85106, -20592, -138936, 76593, 30265, -78950, 35474, -38049,
    171871, 93234, 53443, 90451, -100504, -24317, -164073, 90451, 35741, -93234, 41892, -44933,
    109562, 59434, 34068, 57659, -64067, -15501, -104591, 57659, 22783, -59433, 26705, -28643,
    158036, 85729, 49141, 83170, -92414, -22360, -150866, 83170, 32864, -85729, 38520, -41316,
    107117, 58107, 33308, 56373, -62638, -15155, -102257, 56373, 22275, -58107, 26109, -28004,
    148196, 80392, 46081, 77991, -86658, -20967, -141472, 77990, 30816, -80390, 36122, -38743,
    123763, 67137, 38484, 65133, -72372, -17510, -118148, 65133, 25737, -67137, 30166, -32356,
    140927, 76448, 43821, 74166, -82409, -19939, -134533, 74166, 29306, -76448, 34350, -36843,
};

static const ulong atan_13_x[] = { 683982, 1984933, 2343692, 2809305, 3014557, 6225244, 6367252, 18975991, 22709274, 24208144, 193788912, 201229582, UWORD(2189376182) };
static const ulong atan_13_den = 2;
static const slong atan_13_c[] = {
    893758, -387440, 344740, 738156, 36462, -653018, 732158, 560616, 202968, -58948, -1125574, -560064, -432616,
    1259900, -546161, 485968, 1040553, 51399, -920537, 1032098, 790281, 286117, -83097, -1586683, -789503, -609844,
    1118388, -484816, 431384, 923678, 45626, -817142, 916172, 701516, 253980, -73764, -1408466, -700826, -541346,
    1508738, -654031, 581950, 1246069, 61551, -1102349, 1235944, 946367, 342627, -99509, -1900063, -945435, -730292,
    1354512, -587175, 522462, 1118693, 55259, -989665, 1109604, 849627, 307603, -89337, -1705835, -848791, -655640,
    1599582, -693411, 616990, 1321097, 65257, -1168723, 1310362, 1003349, 363257, -105501, -2014469, -1002361, -774264,
    1019682, -442027, 393312, 842157, 41599, -745023, 835314, 639603, 231565, -67253, -1284159, -638973, -493568,
    1470820, -637594, 567324, 1214752, 60004, -1074644, 1204882, 922582, 334016, -97008, -1852310, -921674, -711938,
    996926, -432163, 384534, 823363, 40671, -728397, 816672, 625329, 226397, -65753, -1255501, -624713, -482554,
    1379246, -597896, 532002, 1139122, 56268, -1007736, 1129866, 865142, 313220, -90968, -1736984, -864290, -667612,
    1151848, -499321, 444290, 951313, 46991, -841589, 943582, 722505, 261579, -75971, -1450605, -721793, -557542,
    1311590, -568568, 505906, 1083244, 53508, -958304, 1074442, 822704, 297856, -86506, -1651780, -821894, -634864,
    1674096, -725713, 645732, 1382639, 68297, -1223167, 1371404, 1050089, 380179, -110415, -2108311, -1049055, -810332,
};

static const ulong atan_16_x[] = { 4079486, 6367252, 7691443, 8296072, 9639557, 10292025, 18975991, 19696179, 22709274, 24208144, 168623905, 193788912, 201229582, 284862638, 599832943, UWORD(2189376182) };
static const ulong atan_16_den = 1;
static const slong atan_16_c[] = {
    -234928, 371891, 1821154, 2095663, 2092544, -619249, 3406969, -1705235, 801522, 537775, -718269, -1808724, 317867, -446879, 1201905, -1341875,
    -331170, 524242, 2567218, 2954184, 2949787, -872934, 4802687, -2403811, 1129878, 758083, -1012519, -2549696, 448086, -629950, 1694284, -1891595,
    -293973, 465359, 2278868, 2622370, 2618467, -774886, 4263249, -2133815, 1002970, 672935, -898793, -2263314, 397757, -559194, 1503982, -1679131,
    -396578, 627783, 3074260, 3537654, 3532389, -1045344, 5751248, -2878579, 1353036, 907809, -1212498, -3053277, 536586, -754369, 2028916, -2265197,
    -356039, 563610, 2760003, 3176028, 3171301, -938487, 5163344, -2584325, 1214726, 815011, -1088554, -2741165, 481735, -677256, 1821516, -2033644,
    -420457, 665583, 3259367, 3750663, 3745081, -1108286, 6097542, -3051904, 1434505, 962470, -1285505, -3237121, 568895, -799791, 2151081, -2401589,
    -268028, 424288, 2077742, 2390928, 2387369, -706497, 3886988, -1945491, 914451, 613544, -819468, -2063561, 362652, -509841, 1371245, -1530936,
    -386611, 612006, 2996996, 3448744, 3443611, -1019072, 5606705, -2806233, 1319031, 884994, -1182025, -2976541, 523100, -735410, 1977924, -2208267,
    -262046, 414819, 2031373, 2337569, 2334090, -690730, 3800241, -1902073, 894043, 599851, -801180, -2017508, 354559, -498463, 1340643, -1496770,
    -362541, 573902, 2810403, 3234025, 3229212, -955624, 5257631, -2631517, 1236908, 829894, -1108432, -2791221, 490532, -689623, 1854779, -2070780,
    -302768, 479282, 2347047, 2700826, 2696806, -798069, 4390797, -2197654, 1032977, 693068, -925683, -2331028, 409657, -575924, 1548978, -1729367,
    -344757, 545750, 2672544, 3075386, 3070809, -908748, 4999728, -2502433, 1176234, 789185, -1054060, -2654303, 466470, -655795, 1763796, -1969202,
    -440043, 696588, 3411200, 3925382, 3919540, -1159914, 6381586, -3194072, 1501329, 1007305, -1345388, -3387917, 595396, -837048, 2251286, -2513463,
    -382676, 605775, 2966488, 3413638, 3408557, -1008698, 5549632, -2777667, 1305604, 875985, -1169992, -2946241, 517775, -727924, 1957790, -2185788,
    -254840, 403411, 1975510, 2273286, 2269903, -671735, 3695735, -1849767, 869457, 583355, -779148, -1962027, 344809, -484755, 1303776, -1455609,
    -365532, 578637, 2833590, 3260707, 3255854, -963509, 5301009, -2653228, 1247113, 836741, -1117577, -2814250, 494579, -695313, 1870081, -2087865,
};

#if HAVE_64_BIT
static const ulong atan_22_x[] = {UWORD(1479406293), UWORD(1892369318), UWORD(2112819717), UWORD(2189376182), UWORD(2701984943), UWORD(2971354082), UWORD(3558066693), UWORD(4038832337), UWORD(5271470807), UWORD(6829998457), UWORD(7959681215), UWORD(8193535810), UWORD(12139595709), UWORD(12185104420), UWORD(12957904393), UWORD(14033378718), UWORD(18710140581), UWORD(18986886768), UWORD(20746901917), UWORD(104279454193), UWORD(120563046313), UWORD(69971515635443)};
static const ulong atan_22_den = 1;
static const slong atan_22_c[] = {
    WORD(-686576870), WORD(1656337239), WORD(-259447943), WORD(-1575862355), WORD(-586963256), WORD(2831731070), WORD(-713071113), WORD(1093399495), WORD(462322718), WORD(-1204188516), WORD(1196364387), WORD(1658902), WORD(-46276061), WORD(42040652), WORD(2649880866), WORD(1607783027), WORD(325822937), WORD(-351517254), WORD(909623840), WORD(-657099816), WORD(-765606746), WORD(241797349),
    WORD(-967843747), WORD(2334881511), WORD(-365734822), WORD(-2221438841), WORD(-827421869), WORD(3991793678), WORD(-1005191768), WORD(1541327578), WORD(651720399), WORD(-1697503042), WORD(1686473637), WORD(2338497), WORD(-65233768), WORD(59263258), WORD(3735445714), WORD(2266436312), WORD(459301363), WORD(-495521756), WORD(1282265372), WORD(-926290960), WORD(-1079249439), WORD(340853388),
    WORD(-859135493), WORD(2072627513), WORD(-324655470), WORD(-1971926729), WORD(-734485807), WORD(3543435230), WORD(-892288583), WORD(1368205594), WORD(578519134), WORD(-1506839423), WORD(1497048841), WORD(2075837), WORD(-57906708), WORD(52606806), WORD(3315880281), WORD(2011870082), WORD(407712613), WORD(-439864730), WORD(1138241267), WORD(-822249917), WORD(-958028093), WORD(302568720),
    WORD(-1158999071), WORD(2796035528), WORD(-437969786), WORD(-2660187206), WORD(-990842975), WORD(4780198435), WORD(-1203723565), WORD(1845749623), WORD(780439342), WORD(-2032770739), WORD(2019562956), WORD(2800365), WORD(-78117854), WORD(70968130), WORD(4473220110), WORD(2714071965), WORD(550016317), WORD(-593390469), WORD(1535520976), WORD(-1109239343), WORD(-1292408099), WORD(408174110),
    WORD(-1040523885), WORD(2510219225), WORD(-393199645), WORD(-2388257588), WORD(-889557039), WORD(4291557060), WORD(-1080676552), WORD(1657073432), WORD(700661283), WORD(-1824976878), WORD(1813119221), WORD(2514106), WORD(-70132492), WORD(63713627), WORD(4015958669), WORD(2436634140), WORD(493792557), WORD(-532732917), WORD(1378556973), WORD(-995850695), WORD(-1160295577), WORD(366449742),
    WORD(-1228784594), WORD(2964390108), WORD(-464340774), WORD(-2820362102), WORD(-1050503502), WORD(5068023211), WORD(-1276202034), WORD(1956885694), WORD(827431069), WORD(-2155167704), WORD(2141164656), WORD(2968980), WORD(-82821478), WORD(75241255), WORD(4742561141), WORD(2877491364), WORD(583133838), WORD(-629119629), WORD(1627977594), WORD(-1176028739), WORD(-1370226431), WORD(432751044),
    WORD(-783310848), WORD(1889703810), WORD(-296002381), WORD(-1797890566), WORD(-669662358), WORD(3230702580), WORD(-813537948), WORD(1247451994), WORD(527460822), WORD(-1373850429), WORD(1364923934), WORD(1892630), WORD(-52796041), WORD(47963892), WORD(3023230928), WORD(1834308642), WORD(371729157), WORD(-401043627), WORD(1037783608), WORD(-749680679), WORD(-873475492), WORD(275864939),
    WORD(-1129870629), WORD(2725764411), WORD(-426962549), WORD(-2593330285), WORD(-965940701), WORD(4660060518), WORD(-1173471088), WORD(1799361483), WORD(760825019), WORD(-1981682307), WORD(1968806468), WORD(2729985), WORD(-76154564), WORD(69184530), WORD(4360797299), WORD(2645860790), WORD(536193080), WORD(-578477135), WORD(1496929630), WORD(-1081361483), WORD(-1259926766), WORD(397915710),
    WORD(-765829642), WORD(1847531151), WORD(-289396474), WORD(-1757766910), WORD(-654717454), WORD(3158602753), WORD(-795382162), WORD(1219612516), WORD(515689440), WORD(-1343190108), WORD(1334462826), WORD(1850392), WORD(-51617788), WORD(46893478), WORD(2955761261), WORD(1793372241), WORD(363433250), WORD(-392093507), WORD(1014623315), WORD(-732950000), WORD(-853982075), WORD(269708441),
    WORD(-1059524736), WORD(2556057963), WORD(-400379805), WORD(-2431869203), WORD(-905801107), WORD(4369924542), WORD(-1100410625), WORD(1687333002), WORD(713455954), WORD(-1858302508), WORD(1846228320), WORD(2560016), WORD(-71413171), WORD(64877092), WORD(4089293490), WORD(2481129152), WORD(502809629), WORD(-542461073), WORD(1403730596), WORD(-1014035776), WORD(-1181483561), WORD(373141426),
    WORD(-884839166), WORD(2134636521), WORD(-334368534), WORD(-2030922964), WORD(-756460202), WORD(3649447961), WORD(-918984132), WORD(1409139660), WORD(595827308), WORD(-1551921145), WORD(1541837648), WORD(2137942), WORD(-59639165), WORD(54180700), WORD(3415085008), WORD(2072061345), WORD(419910586), WORD(-453024632), WORD(1172295245), WORD(-846850045), WORD(-986690441), WORD(311620991),
    WORD(-1007551725), WORD(2430675304), WORD(-380739920), WORD(-2312578392), WORD(-861368722), WORD(4155566039), WORD(-1046432033), WORD(1604564027), WORD(678458702), WORD(-1767146942), WORD(1755665031), WORD(2434439), WORD(-67910131), WORD(61694667), WORD(3888700820), WORD(2359421986), WORD(478145240), WORD(-515851656), WORD(1334873208), WORD(-964294141), WORD(-1123528087), WORD(354837669),
    WORD(-1286025714), WORD(3102481854), WORD(-485971405), WORD(-2951744515), WORD(-1099439660), WORD(5304109606), WORD(-1335652026), WORD(2048044331), WORD(865975726), WORD(-2255563017), WORD(2240907657), WORD(3107286), WORD(-86679594), WORD(78746258), WORD(4963486365), WORD(3011535060), WORD(610298269), WORD(-658426241), WORD(1703814532), WORD(-1230812305), WORD(-1434056411), WORD(452910114),
    WORD(-1118368966), WORD(2698017143), WORD(-422616229), WORD(-2566931147), WORD(-956107784), WORD(4612622835), WORD(-1161525589), WORD(1781044652), WORD(753080103), WORD(-1961509518), WORD(1948764750), WORD(2702195), WORD(-75379339), WORD(68480257), WORD(4316406004), WORD(2618926911), WORD(530734834), WORD(-572588453), WORD(1481691443), WORD(-1070353625), WORD(-1247101180), WORD(393865076),
    WORD(-744769216), WORD(1796723777), WORD(-281438029), WORD(-1709428066), WORD(-636712629), WORD(3071740720), WORD(-773509038), WORD(1186072995), WORD(501507906), WORD(-1306252186), WORD(1297764905), WORD(1799506), WORD(-50198291), WORD(45603901), WORD(2874477399), WORD(1744054245), WORD(353438783), WORD(-381310879), WORD(986721027), WORD(-712793769), WORD(-830497445), WORD(262291420),
    WORD(-1068266212), WORD(2577146400), WORD(-403683088), WORD(-2451933036), WORD(-913274306), WORD(4405978059), WORD(-1109489426), WORD(1701254132), WORD(719342233), WORD(-1873634201), WORD(1861460396), WORD(2581137), WORD(-72002356), WORD(65412352), WORD(4123031695), WORD(2501599398), WORD(506957997), WORD(-546936581), WORD(1415311900), WORD(-1022401951), WORD(-1191231244), WORD(376219983),
    WORD(-839271258), WORD(2024705898), WORD(-317149049), WORD(-1926333436), WORD(-717503621), WORD(3461506790), WORD(-871657809), WORD(1336571052), WORD(565143083), WORD(-1471999502), WORD(1462435290), WORD(2027841), WORD(-56567836), WORD(51390474), WORD(3239213182), WORD(1965353251), WORD(398285812), WORD(-429694534), WORD(1111923774), WORD(-803238520), WORD(-935877343), WORD(295572971),
    WORD(-936636410), WORD(2259595150), WORD(-353941999), WORD(-2149810347), WORD(-800742322), WORD(3863081528), WORD(-972780175), WORD(1491628720), WORD(630706203), WORD(-1642768433), WORD(1632094662), WORD(2263094), WORD(-63130358), WORD(57352362), WORD(3614999296), WORD(2193356911), WORD(444491563), WORD(-479544059), WORD(1240919765), WORD(-896423459), WORD(-1044449916), WORD(329862847),
    WORD(-1239711235), WORD(2990750161), WORD(-468469801), WORD(-2845441424), WORD(-1059844826), WORD(5113089264), WORD(-1287550323), WORD(1974286781), WORD(834788780), WORD(-2174331962), WORD(2160204395), WORD(2995381), WORD(-83557945), WORD(75910318), WORD(4784733109), WORD(2903078693), WORD(588319201), WORD(-634713910), WORD(1642453953), WORD(-1186486262), WORD(-1382410807), WORD(436599168),
    WORD(-732543763), WORD(1767230397), WORD(-276818199), WORD(-1681367652), WORD(-626260935), WORD(3021317824), WORD(-760811818), WORD(1166603502), WORD(493275609), WORD(-1284809940), WORD(1276461979), WORD(1769967), WORD(-49374282), WORD(44855308), WORD(2827292597), WORD(1715425440), WORD(347637054), WORD(-375051627), WORD(970523914), WORD(-701093196), WORD(-816864755), WORD(257985883),
    WORD(-911523298), WORD(2199010843), WORD(-344452100), WORD(-2092169592), WORD(-779272804), WORD(3759504514), WORD(-946697974), WORD(1451635144), WORD(613795697), WORD(-1598722495), WORD(1588334910), WORD(2202416), WORD(-61437706), WORD(55814630), WORD(3518073868), WORD(2134548585), WORD(432573847), WORD(-466686514), WORD(1207648201), WORD(-872388537), WORD(-1016446105), WORD(321018558),
    WORD(-1310818407), WORD(3162293162), WORD(-495340222), WORD(-3008649828), WORD(-1120635247), WORD(5406365074), WORD(-1361401442), WORD(2087527627), WORD(882670470), WORD(-2299046970), WORD(2284109076), WORD(3167190), WORD(-88350649), WORD(80264371), WORD(5059175116), WORD(3069593047), WORD(622063926), WORD(-671119736), WORD(1736661582), WORD(-1254540564), WORD(-1461702920), WORD(461641558),
};
#endif

typedef struct
{
    const ulong * x;
    arb_ptr res;
    slong prec;
    int hyperbolic;
}
atan_work;

static void
parallel_atan_worker(slong i, atan_work * work)
{
    fmpz_t p, q;

    fmpz_init(p);
    fmpz_init(q);

    fmpz_one(p);
    if (work->x[i] == L24_FIXME)
        fmpz_set_str(q, L24_FIXME_STR, 10);
    else
        fmpz_set_ui(q, work->x[i]);

    arb_atan_frac_bsplit(work->res + i, p, q, work->hyperbolic, work->prec);

    fmpz_clear(p);
    fmpz_clear(q);
}

void
arb_log_primes_vec_bsplit(arb_ptr res, slong n, slong prec)
{
    ulong den, prime;
    const ulong * x;
    ulong * primes;
    const slong * c;
    slong i, j, k, wp, ln;
    arb_ptr y;
    arb_t t;
    fmpz_t p, q;
    n_primes_t iter;

    wp = prec + 64;

    switch (n)
    {
#if HAVE_64_BIT
        case 1:
        case 2:
        case 3:
        case 4:
        case 5: ln = 4; x = log_atanh_4_x; den = log_atanh_4_den; c = log_atanh_4_c; break;
        case 6:
        case 7:
        case 8:
        case 9: ln = 8; x = log_atanh_8_x; den = log_atanh_8_den; c = log_atanh_8_c; break;
        case 10:
        case 11:
        case 12: ln = 12; x = log_atanh_12_x; den = log_atanh_12_den; c = log_atanh_12_c; break;
        case 13:
        case 14: ln = 13; x = log_atanh_13_x; den = log_atanh_13_den; c = log_atanh_13_c; break;
        case 15:
        case 16:
        case 17: ln = 16; x = log_atanh_16_x; den = log_atanh_16_den; c = log_atanh_16_c; break;
        case 18:
        case 19:
        case 20:
        case 21: ln = 20; x = log_atanh_20_x; den = log_atanh_20_den; c = log_atanh_20_c; break;
        case 22:
        case 23:
        case 24:
        default: ln = 24; x = log_atanh_24_x; den = log_atanh_24_den; c = log_atanh_24_c; break;
#else
        case 1:
        case 2:
        case 3:
        case 4:
        case 5: ln = 4; x = log_atanh_4_x; den = log_atanh_4_den; c = log_atanh_4_c; break;
        case 6:
        case 7:
        case 8:
        case 9: ln = 8; x = log_atanh_8_x; den = log_atanh_8_den; c = log_atanh_8_c; break;
        case 10:
        case 11:
        case 13:
        default: ln = 13; x = log_atanh_13_x; den = log_atanh_13_den; c = log_atanh_13_c; break;
#endif
    }

    y = _arb_vec_init(ln);
    arb_init(t);
    fmpz_init(p);
    fmpz_init(q);

    primes = flint_malloc(sizeof(ulong) * n);
    n_primes_init(iter);
    for (i = 0; i < n; i++)
        primes[i] = n_primes_next(iter);
    n_primes_clear(iter);

    {
        atan_work work;

        work.x = x;
        work.res = y;
        work.prec = wp;
        work.hyperbolic = 1;
        flint_parallel_do((do_func_t) parallel_atan_worker, &work, ln, -1, FLINT_PARALLEL_STRIDED);
    }

    for (i = 0; i < FLINT_MIN(n, ln); i++)
    {
        arb_dot_si(res + i, NULL, 0, y, 1, c + i * ln, 1, ln, wp);
        if (den == 1)
            arb_set_round(res + i, res + i, prec);
        else
            arb_div_ui(res + i, res + i, den, prec);
    }

    /* todo: sieving instead of factoring */
    /* todo: parallel comp here as well */
    for (i = ln; i < n; i++)
    {
        n_factor_t fac;

        prime = primes[i];

        fmpz_one(p);
        fmpz_set_ui(q, 2 * prime * prime - 1);

        arb_atan_frac_bsplit(res + i, p, q, 1, wp);
        arb_mul_2exp_si(res + i, res + i, 1);

        n_factor_init(&fac);
        n_factor(&fac, (prime - 1) / 2, 1);

        for (j = 0; j < fac.num; j++)
            for (k = 0; k < i; k++)
                if (fac.p[j] == primes[k])
                    arb_addmul_ui(res + i, res + k, fac.exp[j], wp);

        n_factor_init(&fac);
        n_factor(&fac, (primes[i] + 1) / 2, 1);

        for (j = 0; j < fac.num; j++)
            for (k = 0; k < i; k++)
                if (fac.p[j] == primes[k])
                    arb_addmul_ui(res + i, res + k, fac.exp[j], wp);

        arb_mul_2exp_si(res + i, res + i, -1);

        arb_add(res + i, res + i, res + 0, prec);
    }

    _arb_vec_clear(y, ln);
    arb_clear(t);
    fmpz_clear(p);
    fmpz_clear(q);
    flint_free(primes);
}

FLINT_TLS_PREFIX arb_struct _arb_log_p_cache[ARB_LOG_PRIME_CACHE_NUM];
FLINT_TLS_PREFIX slong _arb_log_p_cache_prec = 0;

void _arb_log_p_cleanup(void)
{
    slong i;
    for (i = 0; i < ARB_LOG_PRIME_CACHE_NUM; i++)
        arb_clear(_arb_log_p_cache + i);
    _arb_log_p_cache_prec = 0;
}

arb_srcptr _arb_log_p_cache_vec(void)
{
    return _arb_log_p_cache;
}


void _arb_log_p_ensure_cached(slong prec)
{
    slong i, wp;

    if (_arb_log_p_cache_prec < prec)
    {
        if (_arb_log_p_cache_prec == 0)
        {
            for (i = 0; i < ARB_LOG_PRIME_CACHE_NUM; i++)
                arb_init(_arb_log_p_cache + i);

            flint_register_cleanup_function(_arb_log_p_cleanup);
        }

        wp = prec + 32;

        if (wp <= ARB_LOG_TAB2_PREC - 16)
        {
            for (i = 0; i < ARB_LOG_PRIME_CACHE_NUM; i++)
            {
                slong exp, exp_fix;
                mp_size_t n;
                arb_ptr res = _arb_log_p_cache + i;

                n = ARB_LOG_TAB2_PREC / FLINT_BITS;

                /* exponent of log(prime(i+1)) */
                exp = (i >= 1) + (i >= 4) + (i >= 16) + (i >= 429);

                /* just reading the table is known to give the correct rounding */
                _arf_set_round_mpn(arb_midref(res), &exp_fix, arb_log_p_tab[i], n, 0, wp, ARF_RND_NEAR);
                exp += exp_fix;
                _fmpz_set_si_small(ARF_EXPREF(arb_midref(res)), exp);

                /* 1/2 ulp error */
                _fmpz_set_si_small(MAG_EXPREF(arb_radref(res)), exp - wp);
                MAG_MAN(arb_radref(res)) = MAG_ONE_HALF;
            }
        }
        else
        {
            prec = FLINT_MAX(prec, _arb_log_p_cache_prec * 1.25);

            arb_log_primes_vec_bsplit(_arb_log_p_cache, ARB_LOG_PRIME_CACHE_NUM, prec + 32);
        }

        _arb_log_p_cache_prec = prec;
    }
}

static int factor_smooth(ulong * c, ulong n)
{
    slong i;

    for (i = 0; i < ARB_LOG_PRIME_CACHE_NUM; i++)
        c[i] = 0;

    /* Hardcoded so that the compiler can remove divisions */
    while (n != 1 && n % 2 == 0) { n /= 2; c[0]++; }
    while (n != 1 && n % 3 == 0) { n /= 3; c[1]++; }
    while (n != 1 && n % 5 == 0) { n /= 5; c[2]++; }
    while (n != 1 && n % 7 == 0) { n /= 7; c[3]++; }
    while (n != 1 && n % 11 == 0) { n /= 11; c[4]++; }
    while (n != 1 && n % 13 == 0) { n /= 13; c[5]++; }
    while (n != 1 && n % 17 == 0) { n /= 17; c[6]++; }
    while (n != 1 && n % 19 == 0) { n /= 19; c[7]++; }
    while (n != 1 && n % 23 == 0) { n /= 23; c[8]++; }
    while (n != 1 && n % 29 == 0) { n /= 29; c[9]++; }
    while (n != 1 && n % 31 == 0) { n /= 31; c[10]++; }
    while (n != 1 && n % 37 == 0) { n /= 37; c[11]++; }
    while (n != 1 && n % 41 == 0) { n /= 41; c[12]++; }

    return n == 1;
}

/* todo: use in log_ui in appropriates ranges */
int
_arb_log_ui_smooth(arb_t res, ulong n, slong prec)
{
    ulong c[ARB_LOG_PRIME_CACHE_NUM];

    if (factor_smooth(c, n))
    {
        _arb_log_p_ensure_cached(prec);
        arb_dot_ui(res, NULL, 0, _arb_log_p_cache, 1, c, 1, ARB_LOG_PRIME_CACHE_NUM, prec);
        return 1;
    }
    else
    {
        return 0;
    }
}

void
arb_atan_gauss_primes_vec_bsplit(arb_ptr res, slong n, slong prec)
{
    const ulong * x;
    const slong * c;
    slong i, j, wp, ln;
    arb_ptr y;
    arb_t t;
    fmpz_t p, q;
    ulong den;

    /* not implemented */
    if (n > 64)
        flint_abort();

    wp = prec + 64;

    switch (n)
    {
        case 1:
        case 2:
        case 3: ln = 3; x = atan_3_x; den = atan_3_den; c = atan_3_c; break;
        case 4: ln = 4; x = atan_4_x; den = atan_4_den; c = atan_4_c; break;
        case 5:
        case 6:
        case 7:
        case 8: ln = 8; x = atan_8_x; den = atan_8_den; c = atan_8_c; break;
        case 9:
        case 10:
        case 11:
        case 12: ln = 12; x = atan_12_x; den = atan_12_den; c = atan_12_c; break;
        case 13: ln = 13; x = atan_13_x; den = atan_13_den; c = atan_13_c; break;
        case 14:
        case 15:
        case 16: ln = 16; x = atan_16_x; den = atan_16_den; c = atan_16_c; break;
#if HAVE_64_BIT
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
        case 22:
        default: ln = 22; x = atan_22_x; den = atan_22_den; c = atan_22_c; break;
#else
        default: ln = 16; x = atan_16_x; den = atan_16_den; c = atan_16_c; break;
#endif
    }

    y = _arb_vec_init(ln);
    arb_init(t);
    fmpz_init(p);
    fmpz_init(q);

    {
        atan_work work;

        work.x = x;
        work.res = y;
        work.prec = wp;
        work.hyperbolic = 0;
        flint_parallel_do((do_func_t) parallel_atan_worker, &work, ln, -1, FLINT_PARALLEL_STRIDED);
    }

    for (i = 0; i < FLINT_MIN(n, ln); i++)
    {
        arb_dot_si(res + i, NULL, 0, y, 1, c + i * ln, 1, ln, wp);
        if (den == 1)
            arb_set_round(res + i, res + i, prec);
        else
            arb_div_ui(res + i, res + i, den, prec);
    }

    for (i = ln; i < n; i++)
    {
        double best = 100, t;
        slong xa, xb, ya, yb;
        slong best_j = 0;

        xa = small_gaussian_primes[2 * i];
        xb = small_gaussian_primes[2 * i + 1];

        for (j = 0; j < FLINT_MIN(i, 100); j++)
        {
            ya = small_gaussian_primes[2 * j];
            yb = small_gaussian_primes[2 * j + 1];

            t = (xb*ya - xa*yb) / (double) (xa*ya + xb*yb);

            if (fabs(t) < best)
            {
                best = fabs(t);
                best_j = j;
            }
        }

        ya = small_gaussian_primes[2 * best_j];
        yb = small_gaussian_primes[2 * best_j + 1];

        fmpz_set_si(p, xb*ya - xa*yb);
        fmpz_set_si(q, xa*ya + xb*yb);

        arb_atan_frac_bsplit(res + i, p, q, 0, wp);
        arb_add(res + i, res + i, res + best_j, prec);
    }

    _arb_vec_clear(y, ln);
    arb_clear(t);
    fmpz_clear(p);
    fmpz_clear(q);
}

FLINT_TLS_PREFIX arb_struct _arb_atan_gauss_p_cache[ARB_ATAN_GAUSS_PRIME_CACHE_NUM];
FLINT_TLS_PREFIX slong _arb_atan_gauss_p_cache_prec = 0;

void _arb_atan_gauss_p_cleanup(void)
{
    slong i;
    for (i = 0; i < ARB_ATAN_GAUSS_PRIME_CACHE_NUM; i++)
        arb_clear(_arb_atan_gauss_p_cache + i);
    _arb_atan_gauss_p_cache_prec = 0;
}

arb_srcptr _arb_atan_gauss_p_cache_vec(void)
{
    return _arb_atan_gauss_p_cache;
}

void _arb_atan_gauss_p_ensure_cached(slong prec)
{
    slong i, wp;

    if (_arb_atan_gauss_p_cache_prec < prec)
    {
        if (_arb_atan_gauss_p_cache_prec == 0)
        {
            for (i = 0; i < ARB_ATAN_GAUSS_PRIME_CACHE_NUM; i++)
                arb_init(_arb_atan_gauss_p_cache + i);

            flint_register_cleanup_function(_arb_atan_gauss_p_cleanup);
        }

        wp = prec + 32;

        /* todo */
        if (wp <= ARB_ATAN_TAB2_PREC - 16)
        {
            for (i = 0; i < ARB_ATAN_GAUSS_PRIME_CACHE_NUM; i++)
            {
                slong exp, exp_fix;
                mp_size_t n;
                static const char exponents[24] = {0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1};
                arb_ptr res = _arb_atan_gauss_p_cache + i;

                n = ARB_LOG_TAB2_PREC / FLINT_BITS;

                if (i >= 24)
                    flint_abort();
                /* exponent of 2*atan(x) */
                exp = exponents[i] + 1;

                /* just reading the table is known to give the correct rounding */
                _arf_set_round_mpn(arb_midref(res), &exp_fix, arb_atan_gauss_tab[i], n, 0, wp, ARF_RND_NEAR);
                exp += exp_fix;
                _fmpz_set_si_small(ARF_EXPREF(arb_midref(res)), exp);

                /* 1/2 ulp error */
                _fmpz_set_si_small(MAG_EXPREF(arb_radref(res)), exp - wp);
                MAG_MAN(arb_radref(res)) = MAG_ONE_HALF;
            }
        }
        else
        {
            prec = FLINT_MAX(prec, _arb_atan_gauss_p_cache_prec * 1.25);

            arb_atan_gauss_primes_vec_bsplit(_arb_atan_gauss_p_cache, ARB_ATAN_GAUSS_PRIME_CACHE_NUM, prec + 32);
            _arb_vec_scalar_mul_2exp_si(_arb_atan_gauss_p_cache, _arb_atan_gauss_p_cache, ARB_ATAN_GAUSS_PRIME_CACHE_NUM, 1);
        }

        _arb_atan_gauss_p_cache_prec = prec;
    }
}
